//
//  LHCuttingEngineMgr.h
//  LevelHelperExplodingSprites
//
//  Created by Bogdan Vladu on 3/10/12.
//  Copyright (c) 2012 Bogdan Vladu. All rights reserved.
//

#ifndef __LH_CUTTING_ENGINE_MGR__
#define __LH_CUTTING_ENGINE_MGR__
#include "Box2D/Box2D.h"
#include "cocos2d.h"
#include <vector>
class LHSprite;
using namespace cocos2d;

class LHCuttingEngineMgr
{
public:
    
    virtual ~LHCuttingEngineMgr();
    static LHCuttingEngineMgr* sharedInstance();

    void destroyAllPrevioslyCutSprites();

    //returns all the sprites that were generated by the last cut action.
    //calling this method makes LHCuttingEngineMgr to not retain the sprites anymore
    CCArray* getSprites();
    
    
    //will triangulate only fixture under point - all other fixtures in the body
    //will remain the same
    void splitSprite(LHSprite * oldSprite,
                     CCPoint atPoint);

    //will triangulate all fixtures based on your decision
    //will not create bodies that have mass smaller then mass - this will improve performance
    //usually mass smaller then 0.04 - 0.06 can be ignore - play with this value until it suit your needs
    void splitSprite(LHSprite * oldSprite,
                     CCPoint atPoint,
                     bool triangulateAllFixtures,
                     float ignoreSmallerMass);


    void cutFirstSpriteIntersectedByLine(CCPoint lineA,
                                         CCPoint lineB,
                                         b2World* world);

    void cutFirstSpriteWithTag(int tag,
                               CCPoint intersectedByLineFromPointA,
                               CCPoint intersectedByLineToPointB,
                               b2World* world);

    void cutSprite(LHSprite* oldSprite,
                   CCPoint withLineFromPointA,
                   CCPoint withLineToPointB);

    void cutAllSpritesIntersectedByLine(CCPoint fromPointA,
                                        CCPoint toPointB,
                                        b2World* world);

    void cutAllSpritesWithTag(int tag,
                              CCPoint intersectedByLineFromPointA,
                              CCPoint intersectedByLineToPointB,
                              b2World* world);


    //sprites inside the radius will be cut randomly
    //call [[LHCuttingEngineMgr shareInstance] debugDrawing] to see how explosion is performed
    void cutSpritesFromPoint(CCPoint point,
                             float radius,
                             int numberOfCuts, //must be even
                             b2World* world);

    void cutSpritesWithTag(int tag,
                           CCPoint point,
                           float radius,
                           int numberOfCuts, //must be even
                           b2World* world);

    void explodeSpritesInRadius(float radius,
                                float maxForce,
                                CCPoint pos,
                                b2World* world);

    void implodeSpritesInRadius(float radius,
                                float maxForce,
                                CCPoint pos,
                                b2World* world);

    //use this only for debuging - performance is slow
    void debugDrawing();
    
    
private:
    
    LHCuttingEngineMgr();
  
    std::vector<CCPoint> explosionLines;
    
#if COCOS2D_VERSION >= 0x00020000
    CCDictionary* spritesPreviouslyCut;
    CCGLProgram *mShaderProgram;
	GLint		mColorLocation;
#else
    CCMutableDictionary<std::string>* spritesPreviouslyCut;
#endif
    
    LHSprite * spriteWithVertices(CCPoint* vertices,
                                  int count,
                                  LHSprite* oldSprite);
    
    LHSprite* createNewSpriteFromBodyInfo(b2Body* body, LHSprite* oldSprite);
    
    b2Body* createBodyWithPoints(b2Vec2* verts,
                                 int count,
                                 b2Body* oldBody,
                                 b2Fixture* oldFixture);

    LHSprite* spriteWithVertices(b2Vec2* vertices,
                                 int count,
                                 LHSprite* oldSprite,
                                 b2Body* splitBody,
                                 b2Fixture* fixture,
                                 float mass);
        
    std::vector<b2Vec2> clockwise(std::vector<b2Vec2>& vec);
    
    bool testCentroid(b2Vec2* vs, int count);
    
    bool canCreateFixtureWithThisVertices(b2Vec2* vertices, int32 count);

    void createFixtureWithVertices(std::vector<b2Vec2>& fixtureVertices,
                                   b2Body* body,
                                   b2Fixture* fixture);

    void setInfoOnBody(b2Body* body, b2Body* splitBody);
    
    void splitBody(b2Body* splitBody, b2Vec2 origA, b2Vec2 origB, CCPoint A ,CCPoint B);

    static float distanceBetweenPoints(b2Vec2 point1, b2Vec2 point2);
    
    void explodeSpritesInRadius(float radius,
                                float maxForce,
                                CCPoint pos,
                                b2World* world,
                                bool doSuction);
    
    float randomFloatBetweenSmallAndBig(float smallNumber, float bigNumber);
    
    void  createExplosionWithCuts(int numberOfCuts,
                                  float radius,
                                  CCPoint explosionPoint);
    
    b2Vec2* makeVerticesCounterclockwise(b2Vec2* vertices, int count);
    bool areVerticesCompatibleWithBox2d(b2Vec2* vertices, int count);

};
#endif
